package com.example.oppotest.service;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.MapUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class AdConvTest {

    //这两个值需要替换
    public static final String APP_KEY = "30007127";
    public static final String TOKEN = "HhIfJ7ILdIESUQCPBF692RQYc7GGCl2v";

    public static final String URL = "https://missile.youku.com/api/ad/conv/v2";

    public static void main(String[] args) {
        Map<String, Object> param = new HashMap<>();
        param.put("event_type", "pay");
        param.put("event_time", new Date().getTime());
        //请勿更换trackId，否则debug模式不生效
        param.put("track_id", "test_track_id");
        param.put("utdid", "test_utdid");
        param.put("deep_conv", 0);
        param.put("creative_id", "110001");//必须是数字

        //若为cid的接入类型请打开这段注释
//        Map<String, Object> orderParam = new HashMap<>();
//        orderParam.put("order_id", "1232232");
//        orderParam.put("order_count", 1);
//        orderParam.put("pay_amount", 123);
//        orderParam.put("product_id", "EW1211");
//        orderParam.put("product_name", "测试");
//        orderParam.put("platform", "淘宝");
//        orderParam.put("product_price", 123);
//        orderParam.put("product_category", "女装");
//        param.put("order_info", orderParam);
//        param.put("click_id", "test_click_id_id");

        AdConvInfo advConvInfo = new AdConvInfo();
        advConvInfo.setAppKey(APP_KEY);
        advConvInfo.setContent(param);
        advConvInfo.setDebug(true);//打开debug模式，若验签失败会返回验签信息。正式模式请勿传递此参数。

        //这里的加密方式就是文档中的。
        advConvInfo.setSignature(
                sign(advConvInfo.getAppKey(), TOKEN, toStr(advConvInfo.getContent())));
        try {
            String result = doPostEntityJSON(URL, advConvInfo);
            //结果为success则为正常，若验签失败会返回验签信息
            System.out.println("请求链接为：" + URL);
            System.out.println("本地加签内容为：" + toStr(advConvInfo.getContent()));
            System.out.println("请求返回结果为："+ result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String doPostEntityJSON(String url, Object postReq) {
        RequestConfig requestCong = RequestConfig.custom().setConnectionRequestTimeout(5000)
                .setConnectTimeout(5000).setSocketTimeout(5000).build();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestCong);
        httpPost.setEntity(new StringEntity(JSON.toJSONString(postReq), ContentType.APPLICATION_JSON));

        CloseableHttpClient httpClient = HttpClients.custom().setMaxConnTotal(100).setMaxConnPerRoute(100).setRetryHandler(
                new DefaultHttpRequestRetryHandler(0, false)).disableAutomaticRetries().build();

        CloseableHttpResponse httpResponse = null;
        try {
            httpResponse = httpClient.execute(httpPost);
            return EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);
        } catch (Exception e) {
            return null;
        }
    }

    // 签名
    public static String sign(String appKey, String appSecret, String content) {
        StringBuilder keyBuilder = new StringBuilder();
        keyBuilder.append(appKey).append(content);
        return MD5(encrypt(keyBuilder.toString(), appSecret, "HmacSHA256"));
    }

    // HmacSHA256加密算法获取加密串
    public static String encrypt(String key, String appSecret, String cryptoType) {
        try {
            SecretKeySpec signingKey = getSecretKey(appSecret, cryptoType);
            Mac mac = Mac.getInstance(cryptoType);
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(key.getBytes());
            String hexBytes = byte2hex(rawHmac);
            return hexBytes;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static SecretKeySpec getSecretKey(String appSecret, String cryptoType) {
        try {
            byte[] keyBytes = appSecret.getBytes();
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, cryptoType);
            return secretKey;
        } catch (Exception var4) {
            return null;
        }
    }

    private static String byte2hex(final byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0xFF));
            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            } else {
                hs = hs + stmp;
            }
        }
        return hs;
    }

    public static String toStr(Map<String, Object> params) {
        if (MapUtils.isEmpty(params)) {
            return null;
        }
        List<String> paramNameList = Lists.newArrayList();
        paramNameList.addAll(params.keySet());
        Collections.sort(paramNameList);
        StringBuilder builder = new StringBuilder();
        boolean first = true;
        for (String key : paramNameList) {
            if (first) {
                first = false;
            } else {
                builder.append("&");
            }
            builder.append(key).append("=");
            Object value = params.get(key);
            String valueString = "";
            if (null != value) {
                if (value instanceof Map) {
                    valueString = String.valueOf(new TreeMap<>((Map) value));
                } else if (value instanceof List) {
                    ArrayList<String> temp = new ArrayList<String>((List) value);
                    Collections.sort(temp);
                    valueString = String.valueOf(temp);
                } else {
                    valueString = String.valueOf(value);
                }
            }
            builder.append(valueString);
        }
        return builder.toString();
    }

    public static String MD5(String s) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(s.getBytes("utf-8"));
            return toHex(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static String toHex(byte[] bytes) {

        final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
        StringBuilder ret = new StringBuilder(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
            ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
        }
        return ret.toString();
    }


    @Getter
    @Setter
    static class AdConvInfo {
        /**
         * 回传事件类型
         */
        private String eventType;

        /**
         * 回传时间
         */
        private Long eventTime;

        /**
         * 转化收益，单位分，人民币
         */
        private String convAmount;

        /**
         * 转化数量
         */
        private String convCount;

        /**
         * 用于追踪关联广告投放维度的id
         */
        private String trackId;

        /**
         * 广告投放单元id（排期/计划）
         */
        private String adgroupId;

        /**
         * 广告投放创意id
         */
        private String creativeId;

        /**
         * 回传侧ip
         */
        private String clientIp;

        /**
         * 设备终端idfa原值，iOS上报
         */
        private String idfa;

        /**
         * 设备终端oaid原值
         */
        private String oaid;

        /**
         * 设备终端imei，md5摘要值，安卓上报
         */
        private String imei;

        /**
         * MAC地址，去除分隔符”:”的大写MAC地址取MD5摘要值
         */
        private String mac;

        /**
         * User Agent，需要进行 URL encode之后传值
         */
        private String ua;

        /**
         * 互联网广告标识，版本号以及具体的CAID值，格式为：ver1_caid1，多个之间以逗号分割，例：20210301_xxxxxxxx,20210101_xxxxxx
         */
        private String caid;

        /**
         * 设备utdid
         */
        private String utdid;

        /**
         * 终端机型
         */
        private String model;

        /**
         * 终端品牌
         */
        private String brand;

        /**
         * 系统类型
         * 0-表示Android，1-表示iOS，2-表示Windows Phone，4-表示HarmonyOS，3-表示其他
         */
        private String os;

        /**
         * 回传应用来源标识
         */
        private String appKey;

        /**
         * 签名
         */
        private String signature;

        /**
         * 内容
         */
        private Map<String, Object> content;
        /**
         * 是否是深度转化数据
         */
        private Integer deepConv;
        /**
         * 是否开启debug模式
         */
        private boolean debug;
    }

}
